## -*- coding: utf-8 -*-

#   Copyright (C) 2007, 2008 Yves Junqueira (yves@cetico.org) 
#
#    This file is part of GeekDNS.
#
#    GeekDNS is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    GeekDNS is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with GeekDNS.  If not, see <http://www.gnu.org/licenses/>.

# Please forgive the author for the ugliness of this code.
# Many parts of it are not relevant for GeekDNS, specially the methods 
# handling orders and billing.

from datetime import datetime, timedelta
import logging

import turbogears
from turbogears import controllers, expose, flash
from turbogears import identity, redirect, error_handler, validate
from tgfastdata import DataController
from cherrypy import request, response
from turbogears import widgets, validators
import cherrypy
from kid import XML
from turbogears.toolbox.catwalk import CatWalk 

import model
from model import * 
from geekroot.widgets import OrderFields, OrderSchema 
from geekroot.widgets import ContactFields, ContactSchema
from geekroot.widgets import dict_html_table,planos_fields
from geekroot.widgets import admindevedores_form 
from geekroot.widgets import AdminMailFields,AdminMailSchema
import geekroot.stdvars
from geekroot.stdvars import real
from geekroot import painel, billing
from geekroot import register_controllers

from tools import send_html_mail

order_form = widgets.TableForm(fields=OrderFields(),
  validator=OrderSchema(), submit_text=u'Próximo')
planos_grid = widgets.DataGrid(fields=planos_fields)
contact_form = widgets.TableForm(fields=ContactFields(),
  validator=ContactSchema(), action="./email_contato",
  submit_text=u'Envia')
adminmail_form = widgets.TableForm(fields=AdminMailFields(),
  validator=AdminMailSchema(), action="./submitmail",
    )

log = logging.getLogger("geekroot.controllers")

def locale_pt():
  return 'pt'

turbogears.config.update({'i18n.get_locale' : locale_pt})

class Root(controllers.RootController):
  registration = register_controllers.UserRegistration()
  catwalk = CatWalk(model)
  catwalk = identity.SecureObject(catwalk,
    identity.in_group("admin"))
  admindns = identity.SecureObject(DataController(DNSDomain),
    identity.in_group("admin"))
  admindnsrecord = identity.SecureObject(DataController(DNSRecord),
    identity.in_group("admin"))
  adminusers = identity.SecureObject(DataController(User),
    identity.in_group("admin"))
  adminservers = identity.SecureObject(DataController(Server),
    identity.in_group("admin"))
  adminserverinvoices = identity.SecureObject(DataController(ServerInvoice),
    identity.in_group("admin"))
  painel = painel.SecurePanel()  

  @expose(template=".templates.normal")
  @identity.require(identity.in_group("admin"))
  def admindevedores(self):
    data = ServerInvoice.select(ServerInvoice.q.paid==False)

    return dict(form=admindevedores_form,data=data)

  @expose(template=".templates.adminmail")
  @identity.require(identity.in_group("admin"))
  def sendmail(self,tg_errors=None):
    """Envia email administrativo
    """
    if tg_errors:
       flash("Dados inválidos. Veja abaixo")
    return dict(form=adminmail_form)

  @expose()
  @identity.require(identity.in_group("admin"))
  @error_handler(sendmail)
  def submitmail(self, **kw):
    """Sends one e-mail for each recipients

    Fields:
      "to" is a string of space separate recipients
      "sender"
      "subject"
      "body" - this should probably be HTML text
    """
    sender=kw['sender']
    subject=kw['subject']
    body=kw['body']
    rcpts=kw['rcpts'].split(' ')
    status = {}
    for r in rcpts:
      log.info("Sending message with subject='%s', dest=%s" %
      (subject,r))
      try:
        s = send_html_mail(sender,r,subject,body)
      except Exception,e:
        status[r]='Exception found: %s' % e
      else:
        if s.has_key(r):
          # smtplib's sendmail() returned an error
          status[r]=s[r]

    if len(status) > 0:
      err = 'Erro ao enviar mensagem(s)'
      for k,v in status.iteritems():
        err += '\n%s error: %s' % (k, v)
      flash(err)
    else:
      flash("Emails enviados com sucesso")
    turbogears.redirect(turbogears.url('sendmail'))


  @expose(template=".templates.planos")
  def planos(self, **kw):
    """Mostra planos disponíveis"""
    plans = ServerPlan.select(orderBy=ServerPlan.q.planname)
    data = []
    for plan in plans:
      link_url = turbogears.url('/pedido/%s' % plan.planname)
      link = XML(
        '<b><a name="%s" style="color:#369;text-decoration:underline" \
        href="%s">%s</a></b>' % (plan.planname, link_url, plan.planname)
        )
      r = (link,
        plan.memory_mb, plan.disk_gb, 
        plan.transfer_gb,
        real(plan.price_real)
        )
      data.append(r)
    log.debug(repr(data))
    return dict(grid=planos_grid, data=data)

  @expose(template=".templates.pedido")
  def pedido(self, planname=None, tg_errors=None, **kw):
    """Formulário de início de pedido
    """
    def notfound():
      raise cherrypy.HTTPError(404, message="Produto nao\
        encontrado")

    if tg_errors:
      flash("Dados inválidos. Veja abaixo")
    forward_url = turbogears.url('/salvapedido') 
    planid = kw.get('plan', None)
    plan = find_plan(planname, planid)
    if not plan:
      notfound()
    else:
      return dict(form=order_form, plan=plan, 
        forward_url=forward_url,
        )

  @expose()
  @validate(form=order_form)
  @error_handler(pedido)
  def salvapedido(self, **kw):
    """Salva pedido na sessão.
    Veja tb 'finalizapedido', que finalmente armazena o pedido no
    banco.
    """
    forward_url= turbogears.url('/novousuario')
    attributes = [ 'domainname', 'plan', 'distro','notes' ]
    for atr in attributes:
    # alternativa: colocar formulario com campos "hidden" para salvar o estado.
      log.info("Iniciando pedido: %s = %s" % (atr, kw[atr]))
      cherrypy.session[atr] = kw[atr]
    turbogears.redirect(forward_url)

  @expose(template=".templates.novousuario")
  @error_handler('novousuario')
  def novousuario(self,
    forward_url=turbogears.url('/planos'), tg_errors=None, **kw):
    """Encaminha usuário para login, finalizapedido ou faz o
    registro.
    Essa função é um grande 'roteador' do "carrinho de compras".
    Caso no futuro suportemos outros serviços, essa função
    irá redirecionar os usuários de acordo com as variáveis de 
    sessão.
    """
    # If already logged, redirect to finalizapedido
    previous_url= request.path
    if cherrypy.session.has_key('plan'):
      forward_url=turbogears.url('/finalizapedido')
    if not identity.current.anonymous:
      raise redirect(forward_url)
    return dict(session=cherrypy.session, 
      previous_url=previous_url, form=register_controllers.new_user_form, 
      forward_url=forward_url,
      action="./registration/create")

  @expose()
  @identity.require(identity.not_anonymous())
  def finalizapedido(self):
    """Guarda detalhes do pedido e redireciona para pagamento
    Utiliza dados do pedido armazenados na sessão.
    Cria primeira fatura para pagamento do mês atual,
    proporcionalmente.
    """
    # Provavelmente vindo do painel de controle
    req_items = [ 'plan', 'domainname', 'distro', 'notes' ]
    details = {}
    for i in req_items:
      details[i] = cherrypy.session[i]
      cherrypy.session.pop(i)
    serverplan = \
    ServerPlan.select(ServerPlan.q.id==details['plan'])[0]
    newserver = Server(
      domain=details['domainname'],
      planID=serverplan.id,
      distro=int(details['distro']),
      memory_mb=int(serverplan.memory_mb),
      transfer_gb=int(serverplan.transfer_gb),
      disk_gb=int(serverplan.disk_gb),
      price_real=int(serverplan.price_real),
      notes=details['notes'],
      ownerID=identity.current.user.id
      )
    log.debug("Novo servidor solicitado por %s: %s" % \
    (newserver.domain, newserver.owner.email_address))

    # Cria fatura proporcional
    now = datetime.now()
    paynow = billing.month_perc_bill(newserver.plan.price_real)
     
    paynow_invoice = ServerInvoice(server=newserver, 
      amount_real=paynow,
      description=u'Mensal. proporcional Ref:%s/%s' % \
        (now.year, now.month),
      )
    # Envia e-mail tosquinho notificando novo pedido
    # TODO: Jogar esse lixo em outro lugar.
    subject = "NOVO PEDIDO: %s" % newserver.domain
    body = [u'<html><body>Novo pedido recebido<br/>']
    serv_fmt = so_row_to_dict(newserver)
    user_fmt = so_row_to_dict(identity.current.user)
    body.append(dict_html_table(serv_fmt) + '<br/><br/>')
    body.append(dict_html_table(user_fmt))
    body.append('</body></html>')
    body_str = ''.join(body)
    self.registration.send_email('suporte@yourbase.com.br',
        'suporte@yourbase.com.br', subject, body_str)
    raise redirect(turbogears.url('/painel/pagamento/%s' %
        details['domainname']))

  @expose(template=".templates.hospedagem")
  def hospedagem(self):
    return dict()

  @expose(template=".templates.sobre")
  def sobre(self, tg_errors=None):
    if tg_errors: 
          flash("Dados inválidos. Veja abaixo")
    return dict(contact_form=contact_form)

  @expose()
  @validate(form=contact_form)
  @error_handler(sobre)
  def email_contato(self, **kw):
    """Envia e-mail de contato para suporte@yourbase.com.br.
    Utiliza o 'send_email' do self.registration (instanciado).
    """
    try:
      from_addr = kw['email']
      body = kw['body']
    except KeyError:
      log.error("Formulario de contato incompleto")
      raise cherrypy.HTTPError(400, message=u"Erro no formulário")
    else:
      pass
    subject = "CONTATO yourbase.com.br"
    to_addr = "suporte@yourbase.com.br"
    ip = cherrypy.request.remoteAddr
    referer = cherrypy.request.headers.get('Referer', '')
    log.info("E-mail de contato recebido. From: %s; IP: %s, Referer: %s" % (from_addr, ip, referer))
    log.info("Body: %s" % body)
    self.registration.send_email(to_addr, from_addr, subject, body)
    flash("Obrigado por sua mensagem!\
    Entraremos em contato em breve.")  
    raise redirect(turbogears.url('/sobre#flash'))

  @expose(template="geekroot.templates.welcome")
  # @identity.require(identity.in_group("admin"))
  def index(self):
    return dict(now=datetime.ctime(datetime.now()))

  @expose(template="geekroot.templates.login")
  def login(self, forward_url=None, previous_url=None, *args, **kw):
    #turbogears.i18n.set_session_locale('pt')
    if not identity.current.anonymous \
      and identity.was_login_attempted() \
      and not identity.get_identity_errors():
      raise redirect(forward_url)

    forward_url=None
    previous_url= request.path

    if identity.was_login_attempted():
      msg=_("The credentials you supplied were not correct or "
           "did not grant access to this resource.")
    elif identity.get_identity_errors():
      msg=_("You must provide your credentials before accessing "
           "this resource.")
    else:
      msg=_("Please log in.")
      forward_url = request.headers.get("Referer", "/")
      
    response.status=403
    return dict(message=msg, previous_url=previous_url, logging_in=True,
          original_parameters=request.params,
          forward_url=forward_url)

  @expose(template="geekroot.templates.retornopag")
  def retornopag(self, **kw):
    """Recebe POST da PagSeguro e GETs do cliente
    O POST da PagSeguro é feito quando há transações e mudança de status
    em pagamentos.
    
    O GET do cliente é feito ao final da compra e não contém nenhum dado
    relevante.
    """
    # TODO(yvesj): verify if the provided order info matches our order...
    log.info("== Retorno pagseguro (debug) ==")
    for k, v in kw.iteritems():
      log.info("retornopag: %s=%s" % (k, v))
    log.info("== fim ==")
    if kw.has_key('ProdID_1'):
      inv_s = ServerInvoice.select(ServerInvoice.q.pubid==kw['ProdID_1'])
      log.info("PG: Invoices encontrados (=1?): %s" % inv_s.count())
      if inv_s.count() == 1:
        invoice = inv_s[0]
        log.info("PG: Invoice id=%s server=%s amount_real=%s" % 
          (invoice.id, invoice.server.domain, invoice.amount_real))
        # se status é "Completo" ou "Aprovado", muda 'paid=True'
        if (kw.has_key("StatusTransacao") and (
          (kw["StatusTransacao"] == "Completo") or
          (kw["StatusTransacao"] == "Aprovado"))
          and (kw["VendedorEmail"] == "yves@yourbase.com.br")):
          log.info("PG: invoice pago!")
          invoice.paid=True
    
    return dict()

  @expose()
  def logout(self):
    identity.current.logout()
    raise redirect("/")
